/******************************************************************************
 * * cale_api.c - implementation of calendar interface
 *
 * *(C) Copyright 2019 Asr International Ltd.
 * * All Rights Reserved
 * ******************************************************************************/
#include "cale_global.h"

LV_IMG_DECLARE(calendar);

/**
 * Calendar APP main entrance
 * param (in) void
 * return  void
 */
VOID Cale_Main(VOID)
{
    printf("Calendar APP\n");
    Display_Calendar();
}

/**
 * Reset calendar module
 * param (in) VOID
 * return  VOID
 */
VOID Framework_Calendar_Reset_Req(VOID)
{
    _lv_ll_clear(&g_CalendarMng.Reminder);
}

/**
 * Initiate calendar module
 * param (in) VOID
 * return  VOID
 */
VOID Framework_Calendar_Init_Req(VOID)
{
    If_Framework_Reg_Info_t *RegInfo;
    NV_UI_Calendar_t CalenNv;
    UINT8 i;
    UI_Reminder_t * Node;
    UI_Reminder_t * Reminder;

    // register APP
    RegInfo             = (If_Framework_Reg_Info_t *)Hal_Mem_Alloc(sizeof(If_Framework_Reg_Info_t));
    RegInfo->NameTextId = PHONE_TEXT_ID_CALENDAR;
    RegInfo->AppImage   = IMG_MENU_CALENDAR;
    RegInfo->AppFunc    = Cale_Main;
    Framework_App_Register_Req(RegInfo);

    // init global variable
    Hal_Mem_Set(&g_CalendarMng, 0, sizeof(UI_Calendar_Mng_t));

    _lv_ll_init(&g_CalendarMng.Reminder, sizeof(UI_Reminder_t));

    // Read NV
    UI_NV_Read_Req(NV_SECTION_UI_CALENDAR, 0, sizeof(NV_UI_Calendar_t), (UINT8*)(&CalenNv));
    for(i = 0; i < NV_CALENDAR_MAX_REMINDER_NUM; i++)
    {
        if(0 != CalenNv.Reminder[i].Year)
        {
            printf("%s: reminder[%d],%d/%d/%d,%d:%d,%s\n", __FUNCTION__,i,
                   CalenNv.Reminder[i].Year,CalenNv.Reminder[i].Mon,CalenNv.Reminder[i].Day,
                   CalenNv.Reminder[i].Hour,CalenNv.Reminder[i].Min,CalenNv.Reminder[i].Text);

            // sort the reminder with date and time
            Node = _lv_ll_get_head(&g_CalendarMng.Reminder);
            while (Node)
            {
                if (0 > UI_Cale_Compare_Reminder_Time(&CalenNv.Reminder[i], &Node->Info))
                {
                    Reminder = _lv_ll_ins_prev(&g_CalendarMng.Reminder, Node);
                    break;
                }
                Node = _lv_ll_get_next(&g_CalendarMng.Reminder, Node);
            }
            if (NULL == Node)
            {
                Reminder = _lv_ll_ins_tail(&g_CalendarMng.Reminder);
            }
            Hal_Mem_Copy(&Reminder->Info, &CalenNv.Reminder[i], sizeof(NV_UI_Calendar_Reminder_t));
            Reminder->IndexInNV = i;
        }
    }
}

/**
 * Process UI input char number event
 * param (in) Len: UINT8. 0 means backspace
 * return  void
 */
VOID UI_Cale_Input_Handler(UINT8 Len)
{
    const INT8 *TaTxt;
    UINT8 TaTxtLen;
    INT8 TxtNumLeft[3] = {};
    UI_Normal_NoTitle_Label_Ta_Desc_t *pTmpDesc;
    printf("%s: Len %d, txt left %d\n", __FUNCTION__, Len, g_CalendarMng.ReminderTxtLeft);
    pTmpDesc = (UI_Normal_NoTitle_Label_Ta_Desc_t *)g_CalendarMng.CurrentDesc;

    if (0 == Len)
    {
        TaTxt    = lv_textarea_get_text(pTmpDesc->ContTa.TextArea);
        TaTxtLen = strlen(TaTxt);

        if(128 < (UINT8)TaTxt[TaTxtLen - 3])
        {// unicode chinese
            g_CalendarMng.ReminderTxtLeft += 3;
        }
        else
        {
            g_CalendarMng.ReminderTxtLeft += 1;
        }
    }
    else if (Len > g_CalendarMng.ReminderTxtLeft)
    {
        return;
    }
    else
    {
        g_CalendarMng.ReminderTxtLeft -= Len;
    }

    sprintf(TxtNumLeft, "%d", g_CalendarMng.ReminderTxtLeft);
    lv_label_set_text(pTmpDesc->ContLabelTr.Label, TxtNumLeft);

    if (UI_CALENDAR_MAX_REMINDER_INPUT_LEFT == g_CalendarMng.ReminderTxtLeft)
    {
        lv_label_set_text(lv_obj_get_child(pTmpDesc->ButtonCont.ButtonR.Button, NULL),
                          lv_lang_get_text(PHONE_TEXT_ID_BACK));
    }
    else
    {
        lv_label_set_text(lv_obj_get_child(pTmpDesc->ButtonCont.ButtonR.Button, NULL),
                          lv_lang_get_text(PHONE_TEXT_ID_CLEAR));
    }
}

/**
 * Alarm informs calendar to check which alarm is ringing during power off
 * param (in) CurTime: hal_rtc_t *
 * param (in) SecondAlarm: UINT32, the nearest time of alarm to the current time
 * return  INT8: 1 if calendar alarm is not ringing,
 *               0 if calendar alarm is ringing at the same time
 *               -1 if calendar alarm is ringing
 */
INT8 Alarm_Calendar_Check_PowerOff_Alarm(hal_rtc_t *CurTime, UINT32 SecondAlarm)
{
    UI_Reminder_t             *AlarmReminder;
    hal_rtc_t                 Alarm;
    UINT32                    SecondTmp = 0;

    printf("%s: alarm time %d in seconds\n", __FUNCTION__, SecondAlarm);

    AlarmReminder = _lv_ll_get_head(&g_CalendarMng.Reminder);
    g_CalendarMng.AlarmReminder = NULL;
    while (AlarmReminder)
    {
        if (0xFF != AlarmReminder->Info.Hour)
        {
            Alarm.tm_year = AlarmReminder->Info.Year;
            Alarm.tm_mon  = AlarmReminder->Info.Mon;
            Alarm.tm_mday = AlarmReminder->Info.Day;
            Alarm.tm_hour = AlarmReminder->Info.Hour;
            Alarm.tm_min  = AlarmReminder->Info.Min;
            Alarm.tm_sec  = 0;
            SecondTmp = UI_Time_to_Seconds(&Alarm);
            printf("%s: cale alarm, %d/%d/%d,%d:%d, sec %d\n",
                   __FUNCTION__, AlarmReminder->Info.Year,
                   AlarmReminder->Info.Mon, AlarmReminder->Info.Day,
                   AlarmReminder->Info.Hour, AlarmReminder->Info.Min,
                   SecondTmp);
            if ((CurTime->tm_year == AlarmReminder->Info.Year)
                && (CurTime->tm_mon == AlarmReminder->Info.Mon)
                && (CurTime->tm_mday == AlarmReminder->Info.Day)
                && (CurTime->tm_hour == AlarmReminder->Info.Hour)
                && (CurTime->tm_min == AlarmReminder->Info.Min)
                && (SecondTmp >= SecondAlarm))
            {
                g_CalendarMng.AlarmReminder = AlarmReminder;
                break;
            }
        }
        AlarmReminder = _lv_ll_get_next(&g_CalendarMng.Reminder, AlarmReminder);
    }
    if (g_CalendarMng.AlarmReminder)
    {
        /*create calendar alarm interface*/
        UI_Cale_Alarm_Ring_Start();
        if (SecondTmp == SecondAlarm)
        {
            return(0);
        }
        else
        {
            return(-1);
        }
    }

    return(1);
}

/**
 * Alarm gets the alarm information of reminder from calendar
 * param (in) CurTime: UINT32, current time in seconds
 * param (in) AlarmTime: UINT32, alarm time in seconds from alarm module, invalid if 0xFFFFFFFF
 * param (out) Info: If_Alarm_Calendar_Info_t *Info, invalid if CallBack is NULL
 * return  INT8, 1 if calendar alarm is not set,
 *               0 if alarm and calendar alarm is set at the same time
 *               -1 if only calendar alarm is set
 */
INT8 Alarm_Calendar_Get_Alarm_Info_Req(UINT32 CurTime,
                                       UINT32 AlarmTime,
                                       If_Alarm_Calendar_Info_t *Info)
{
    hal_rtc_t     Alarm = {0};    // Alarm time
    UINT32        SecondAlarm = 0;
    UI_Reminder_t *Reminder;

    if (NULL == Info)
    {
        printf("%s: Info is NULL\n", __FUNCTION__);
        return(1);
    }

    if (CurTime >= AlarmTime)
    {
        printf("%s: error happened in alarm module\n", __FUNCTION__);
        AlarmTime = 0xFFFFFFFF;
    }

    if (g_CalendarMng.AlarmReminder)
    {
        Alarm.tm_min  = g_CalendarMng.AlarmReminder->Info.Min;
        Alarm.tm_hour = g_CalendarMng.AlarmReminder->Info.Hour;
        Alarm.tm_mday = g_CalendarMng.AlarmReminder->Info.Day;
        Alarm.tm_mon  = g_CalendarMng.AlarmReminder->Info.Mon;
        Alarm.tm_year = g_CalendarMng.AlarmReminder->Info.Year;
        SecondAlarm   = UI_Time_to_Seconds(&Alarm);
        printf("%s: AlarmTime %d, Reminder %d,%d/%d/%d,%d:%d\n",
               __FUNCTION__, AlarmTime, SecondAlarm, g_CalendarMng.AlarmReminder->Info.Year,
               g_CalendarMng.AlarmReminder->Info.Mon, g_CalendarMng.AlarmReminder->Info.Day,
               g_CalendarMng.AlarmReminder->Info.Hour, g_CalendarMng.AlarmReminder->Info.Min);
        if (CurTime >= SecondAlarm)
        {
            printf("%s: the time of AlarmReminder is error!\n", __FUNCTION__);
            g_CalendarMng.AlarmReminder = NULL;
        }
        else if (AlarmTime < SecondAlarm)
        {
            g_CalendarMng.AlarmReminder = NULL;
            return(1);
        }
        else if (AlarmTime == SecondAlarm)
        {
            Info->CallBack = NULL;
            return(0);
        }
        else
        {
            Info->CallBack = NULL;
            return(-1);
        }
    }
    if (NULL == g_CalendarMng.AlarmReminder)
    {
        Reminder = _lv_ll_get_head(&g_CalendarMng.Reminder);
        while (Reminder)
        {
            if (0xFF != Reminder->Info.Hour)
            {
                Alarm.tm_min  = Reminder->Info.Min;
                Alarm.tm_hour = Reminder->Info.Hour;
                Alarm.tm_mday = Reminder->Info.Day;
                Alarm.tm_mon  = Reminder->Info.Mon;
                Alarm.tm_year = Reminder->Info.Year;
                SecondAlarm   = UI_Time_to_Seconds(&Alarm);
                if (AlarmTime < SecondAlarm)
                {
                    break;
                }
                if (CurTime < SecondAlarm)
                {  // priority to set calendar alarm
                    g_CalendarMng.AlarmReminder = Reminder;
                    break;
                }
            }
            Reminder = _lv_ll_get_next(&g_CalendarMng.Reminder, Reminder);
        }

        if (g_CalendarMng.AlarmReminder)
        {
            Info->AlarmTime.Year  = g_CalendarMng.AlarmReminder->Info.Year;
            Info->AlarmTime.Month = g_CalendarMng.AlarmReminder->Info.Mon;
            Info->AlarmTime.Day   = g_CalendarMng.AlarmReminder->Info.Day;
            Info->AlarmTime.WDay  = g_CalendarMng.AlarmReminder->Info.Wday;
            Info->AlarmTime.Hour  = g_CalendarMng.AlarmReminder->Info.Hour;
            Info->AlarmTime.Min   = g_CalendarMng.AlarmReminder->Info.Min;
            Info->CallBack        = UI_Cale_Alarm_Ring_Start;
            printf("%s: %d/%d/%d,%d:%d\n",
                   __FUNCTION__, Info->AlarmTime.Year,Info->AlarmTime.Month,
                   Info->AlarmTime.Day,Info->AlarmTime.Hour, Info->AlarmTime.Min);
            if (AlarmTime == SecondAlarm)
            {
                return(0);
            }
            else
            {
                return(-1);
            }
        }
        else
        {
            return(1);
        }
    }

    return(1);
}

/**
 * Alarm informs calendar to clear the rtc alarm
 * param (in) VOID
 * return  VOID
 */
VOID Alarm_Calendar_Clear_Alarm_Req(VOID)
{
    g_CalendarMng.AlarmReminder = NULL;
}
